﻿using System;
namespace NetworkLibrary
{
    public class IndexSet<T>
    {
        private Entry[] _items;
        private int _length;
        private int _index;
        private struct Entry
        {
            public bool Has;
            public T Value;
        }
        public IndexSet(int capacity = 4)
        {
            _items = new Entry[capacity];
            _length = 0;
            _index = 0;
        }
        public int Count { get => _length; }
        public T this[int index]
        {
            get => _items[index].Value;
        }
        public T Pop(int index)
        {
            ref var entry = ref _items[index];
            entry.Has = false;
            var item = entry.Value;
            entry.Value = default;
            _length--;
            return item;
        }
        public void Pop(T item)
        {
            var index = _index;
            do
            {
                ref var entry = ref _items[index--];
                if (index < 0)
                    index = _items.Length - 1;
                if (entry.Has && Equals(entry.Value, item))
                {
                    entry.Has = false;
                    entry.Value = default;
                    _length--;
                    return;
                }
            }
            while (index != _index);
        }
        public T Push(Func<int, T> item)
        {
            if (_length + 1 > _items.Length)
            {
                var size = Math.Max((_items.Length == 0) ? 4 : (_items.Length * 2), _items.Length + 1);
                size = (int)Math.Min((uint)size, 2146435071u);
                var items = new Entry[size];
                if (_items.Length > 0)
                {
                    Array.Copy(_items, items, _items.Length);
                }
                _items = items;
            }
            var index = _index;
            do
            {
                ref var entry = ref _items[index];
                if (!entry.Has)
                {
                    _index++;
                    if (_index == _items.Length)
                    {
                        _index = 0;
                    }
                    _length++;
                    entry.Has = true;
                    entry.Value = item(index);
                    return entry.Value;
                }
                index++;
                if (index == _items.Length)
                {
                    index = 0;
                }
            } while (index != _index);

            throw new Exception("未知错误！");
        }
        public int Push(T item)
        {
            var index = -1;
            Push((i) =>
            {
                index = i;
                return item;
            });
            return index;
        }
    }
}
